#include "ch32f103_nrf24.h"

#define CSN_GPIO_PORT	GPIOA
#define CSN_GPIO_PIN	GPIO_Pin_4
#define CLK_GPIO_PORT	GPIOA
#define CLK_GPIO_PIN	GPIO_Pin_5
#define MISO_GPIO_PORT	GPIOA
#define MISO_GPIO_PIN	GPIO_Pin_6
#define MOSI_GPIO_PORT	GPIOA
#define MOSI_GPIO_PIN	GPIO_Pin_7
#define CE_GPIO_PORT	GPIOA
#define CE_GPIO_PIN	GPIO_Pin_8
#define IRQ_GPIO_PORT	GPIOA
#define IRQ_GPIO_PIN	GPIO_Pin_9

static void nrf24_port_init()
{
	// GPIO and Clock Init
	GPIO_InitTypeDef GPIO_InitStructure = {0};
	SPI_InitTypeDef SPI_InitStructure = {0};

	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE );
	
	// CSN
	GPIO_InitStructure.GPIO_Pin = CSN_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init( CSN_GPIO_PORT, &GPIO_InitStructure );

	// CLK
	GPIO_InitStructure.GPIO_Pin = CLK_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init( CLK_GPIO_PORT, &GPIO_InitStructure );

	// MISO
	GPIO_InitStructure.GPIO_Pin = MISO_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init( MISO_GPIO_PORT, &GPIO_InitStructure );

	// MOSI
	GPIO_InitStructure.GPIO_Pin = MOSI_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init( MOSI_GPIO_PORT, &GPIO_InitStructure );
	
//	// CSN
//	GPIO_InitStructure.GPIO_Pin = CSN_GPIO_PIN;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_Init( CSN_GPIO_PORT, &GPIO_InitStructure );
//	
//	// IRQ
//	GPIO_InitStructure.GPIO_Pin = IRQ_GPIO_PIN;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_Init( IRQ_GPIO_PORT, &GPIO_InitStructure );
	
	// SPI Init
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init( SPI1, &SPI_InitStructure );

    SPI_Cmd( SPI1, ENABLE );
}

static void nrf24_port_deinit()
{
	SPI_I2S_DeInit(SPI1);
    SPI_Cmd(SPI1, DISABLE);
}

static uint8_t nrf24_port_transfer(uint8_t data)
{
	/* The reception and transmission of SPI will not be blocked,
	 * and only FF or 0 will be read from the bus when an exception occurs.
	 * So no timeout mechanism will be implemented.
	 */
	while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
	SPI_I2S_SendData(SPI1, data);
	
	while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
	return (uint8_t)SPI_I2S_ReceiveData(SPI1);
}

static void nrf24_port_ioctl(uint8_t cmd, uint8_t* opcode)
{
	switch(cmd)
	{
		case NRF24_PORT_CMD_CSN_ENABLE:
			GPIO_ResetBits( CSN_GPIO_PORT, CSN_GPIO_PIN );
			break;
		case NRF24_PORT_CMD_CSN_DISABLE:
			GPIO_SetBits( CSN_GPIO_PORT, CSN_GPIO_PIN );
			break;
		case NRF24_PORT_CMD_CE_ENABLE:
			GPIO_ResetBits( CE_GPIO_PORT, CE_GPIO_PIN );
			break;
		case NRF24_PORT_CMD_CE_DISABLE:
			GPIO_SetBits( CE_GPIO_PORT, CE_GPIO_PIN );
			break;
		case NRF24_PORT_CMD_UNKNOW:
		default:
			break;
	}
}

static nrf24_port_t nrf24_port = {
	.init = nrf24_port_init,
	.deinit = nrf24_port_deinit,
	.transfer = nrf24_port_transfer,
	.ioctl = nrf24_port_ioctl,
};

nrf24_port_t* get_nrf24_port(void)
{
	return &nrf24_port;
}
